﻿using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Zocono.Infrastructure.Common;
using Zocono.WCS.Domain.DomainRepository;
using Zocono.WCS.Domain.EntityInfo;
using Zocono.WCS.Domain.PlcBytesObject;
using Zocono.WCS.Domain.PlcConnectPoolDomain;
using Zocono.WCS.Domain.ProcessModuleDomain;
using Zocono.WCS.Infrastructure.ApllicationDto.Enums;
using Zocono.WCS.WMSApiDomain.WebApi;

namespace Zocono.WCS.Domain.EquipmentProcessDomain.PlanarGeneralMessage
{
    /// <summary>
    /// 到达（下料台）DO任务完成
    /// </summary>
    public class ArriveDoFinishTaskService : IPlanarGeneralPlcActionProcessService
    {
        private readonly ILogUtil _LogUtil;
        private readonly ISnowflake _Snowflake;
        private readonly IPlcConnectionPool _PlcConnectionPool;
        private readonly IWorkTaskInfoRepository _WorkTaskInfoRepository;
        private readonly IRouteDetailInfoRepository _RouteDetailInfoRepository;
        private readonly IPlcWriteDbInfoRepository _PlcWriteDbInfoRepository;
        private readonly ITaskRouteDetailRecordInfoRepository _TaskRouteDetailRecordInfoRepository;
        private readonly IPlcConnectionStateInfoRepository _IPlcConnectionStateInfoRepository;

        public ArriveDoFinishTaskService(ILogUtil logUtil
            , ISnowflake snowflake
            , IPlcConnectionPool plcConnectionPool
            , IWorkTaskInfoRepository workTaskInfoRepository
            , IRouteDetailInfoRepository routeDetailInfoRepository
            , IPlcWriteDbInfoRepository plcWriteDbInfoRepository
            , ITaskRouteDetailRecordInfoRepository taskRouteDetailRecordInfoRepository
            , IPlcConnectionStateInfoRepository plcConnectionStateInfoRepository)
        {
            _LogUtil = logUtil;
            _Snowflake = snowflake;
            _PlcConnectionPool = plcConnectionPool;
            _WorkTaskInfoRepository = workTaskInfoRepository;
            _RouteDetailInfoRepository = routeDetailInfoRepository;
            _PlcWriteDbInfoRepository = plcWriteDbInfoRepository;
            _TaskRouteDetailRecordInfoRepository = taskRouteDetailRecordInfoRepository;
            _IPlcConnectionStateInfoRepository = plcConnectionStateInfoRepository;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="plcActionMessage">PLC动作报文</param>
        /// <param name="wcsActionMessage"></param>
        /// <param name="planarEquipmentDbObject"></param>
        /// <param name="plcStateMassge"></param>
        /// <returns></returns>
        public async Task ProcessActionMessageAsync(BytesObjectBase plcActionMessage, BytesObjectBase wcsActionMessage, EquipmentDbObject planarEquipmentDbObject/*, BytesObjectBase plcStateMassge*/)
        {
            /*
            * 处理逻辑
            * 1. 验证plc是否在线
            * 2. 验证wcs任务，验证wcs当前子任务(待执行、执行中)，当前子任务已经是SC完成后更新了
            * 3. 组织plc报文，写入plc
            * 4. 写入plc是否成功，成功，结束任务，上报wms,失败，不往下操作
            */
            var plcMessage = plcActionMessage as PlanarGeneralPlcActionBO;//Plc的动作报文
            var wcsMessage = wcsActionMessage as PlanarGeneralWcsActionBO;//Wcs的动作报文
                                                                          //var plcStateBo = plcStateMassge as PlcOnLineStateBO;//Plc在线离线报文 没有设备信息

            var plcConn = _PlcConnectionPool.S7GetWritePlcConnection(plcMessage.PlcConnectionID);
            //1. 验证plc是否在线
            var plcIPStates = await _IPlcConnectionStateInfoRepository.GetFirstAsync(l => l.PlcConnectionID == plcMessage.PlcConnectionID && l.Connected == true);
            if (plcIPStates == null)
            {
                _LogUtil.Info($"请求巷道分配失败：设备编号{plcMessage.EquipmentCode}{plcConn.IP}plc已离线");
                return;
            }
            //if (plcStateBo.PlcState == 0)
            //{
            //    var plcConnection = _PlcConnectionPool.S7GetWritePlcConnection(plcStateBo.PlcConnectionID);
            //    _LogUtil.Info($"到达DO完成任务(ArriveDoFinishTaskService.ProcessActionMessageAsync)处理失败：设备({plcMessage.EquipmentCode})，PLC({plcConnection?.IP ?? plcStateBo.PlcConnectionID.ToString()})已离线");

            //    return;
            //}

            //2. 验证wcs任务，验证wcs当前子任务
            var exp = Expressionable.Create<WorkTaskInfo>();
            exp.AndIF(true, it => it.TaskCode == plcMessage.TaskCode &&
            it.TaskState == EnumTaskState.Executing &&
            it.TaskProcessState == EnumTaskProcessState.ScUnloaded);
            var task = await _WorkTaskInfoRepository.GetFirstAsync(exp.ToExpression());
            if (task == null)
            {
                _LogUtil.Info($"到达DO完成任务(ArriveDoFinishTaskService.ProcessActionMessageAsync)处理失败：设备({plcMessage.EquipmentCode}),任务号({plcMessage.TaskCode})执行中的任务数据异常");

                return;
            }

            if (task.CurrentDetailTaskState == EnumDetailTaskState.Finish)
            {
                _LogUtil.Info($"到达DO完成任务(ArriveDoFinishTaskService.ProcessActionMessageAsync)处理成功：设备({plcMessage.EquipmentCode}),任务号({task.TaskCode})当前子任务状态{EnumDetailTaskState.Finish.ToString()},无需操作");

                return;
            }

            //未执行（待执行）
            //执行中
            //3. 组织报文，写入plc
            var objectType = typeof(PlanarGeneralWriteWcsAction).Name;
            var writeConfig = await _PlcWriteDbInfoRepository.GetFirstAsync(it => it.EquipmentCode == plcMessage.EquipmentCode && it.ObjectType == objectType);
            if (writeConfig == null)
            {
                _LogUtil.Info($"到达DO完成任务(ArriveDoFinishTaskService.ProcessActionMessageAsync)处理失败：设备({plcMessage.EquipmentCode})获取PLC写入配置失败");

                return;
            }

            //plc报文什么握手类型则回什么握手类型
            PlanarGeneralWriteWcsAction writeBo = new PlanarGeneralWriteWcsAction(
                writeConfig.PlcConnectionId,
                writeConfig.ID,
                writeConfig.DbCode,
                writeConfig.DbStart,
                objectType,
                writeConfig.EquipmentCode.ToInt32(),
                plcMessage.ActionType,
                task.CurrentToEquipment.ToInt32(),
                task.TaskCode,
                task.PalletCode,
                plcMessage.PalletType,
                alrmCode: plcMessage.AlrmCode);

            if (plcConn == null)
            {
                _LogUtil.Info($"到达DO完成任务(ArriveDoFinishTaskService.ProcessActionMessageAsync)处理失败：设备({writeBo.EquipmentCode})获取连接({writeBo.PlcConnectionID})失败");

                return;
            }

            var writeResult = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
            if (writeResult == false)
            {
                _LogUtil.Info($"到达DO完成任务(ArriveDoFinishTaskService.ProcessActionMessageAsync)处理失败：设备{writeBo.EquipmentCode}),PLC(IP{plcConn.IP}写入报文失败");

                return;
            }

            //5.写入成功，结束任务，上报wms
            task.TaskState = EnumTaskState.Finish;
            task.UpdateTime = DateTime.Now;
            task.CurrentDetailTaskState = EnumDetailTaskState.Finish;
            task.CurrentUpdateTime = DateTime.Now;
            task.TaskProcessState = EnumTaskProcessState.ScUnloaded;
            TaskRouteDetailRecordInfo taskRouteDetailRecordInfo = new TaskRouteDetailRecordInfo();
            taskRouteDetailRecordInfo.ID = _Snowflake.GetId();
            taskRouteDetailRecordInfo.TaskID = task.ID;
            taskRouteDetailRecordInfo.RouteDetailID = task.CurrentRounteDetailID;
            taskRouteDetailRecordInfo.DetailTaskState = EnumDetailTaskState.Finish;
            taskRouteDetailRecordInfo.DispatchType = task.CurrentDispatchType;
            taskRouteDetailRecordInfo.FromEquipment = task.CurrentFromEquipment;
            taskRouteDetailRecordInfo.FromCargo = task.CurrentFromCargo;
            taskRouteDetailRecordInfo.ToEquipment = task.CurrentToEquipment;
            taskRouteDetailRecordInfo.ToCargo = task.CurrentToCargo;
            taskRouteDetailRecordInfo.CreateTime = task.CurrentCreateTime;
            taskRouteDetailRecordInfo.UpdateTime = task.CurrentUpdateTime;

            WMSApiDomain.WebApi.HeaderResult<bool> uploadResult = new();
            try
            {
                uploadResult = await WCSMessageWithWMSApi.WCSNoticeTaskAutoCompleteAsync(task.WmsTaskCode,plcMessage.PalletBarcode,plcMessage.EquipmentCode);
                if (uploadResult.IsSucceed)
                {
                    task.UploadWmsState = EnumUploadWmsState.Succeed;
                }
                else
                {
                    task.UploadWmsState = EnumUploadWmsState.Failed;
                }
                task.UploadWmsTime = DateTime.Now;
            }
            catch (Exception ex)
            {
                _LogUtil.Info($"到达DO完成任务(ArriveDoFinishTaskService.ProcessActionMessageAsync)上传WMS异常：设备{writeBo.EquipmentCode}),任务号{task.TaskCode}上传WMS异常，异常信息：{ex.Message}");
            }

            await _WorkTaskInfoRepository.UpdateAsync(task);
            await _TaskRouteDetailRecordInfoRepository.InsertAsync(taskRouteDetailRecordInfo);

            _LogUtil.Info($"到达DO完成任务(ArriveDoFinishTaskService.ProcessActionMessageAsync)处理成功：设备{plcMessage.EquipmentCode}),PLC(IP{plcConn.IP}");
        }
    }
}
